// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
import '../elements/entities.dart';
import '../elements/names.dart';
import '../elements/types.dart' show DartType;
import '../js_model/js_world.dart';
import '../serialization/serialization.dart';
import '../universe/member_hierarchy.dart';
import '../universe/record_shape.dart';
import '../universe/selector.dart';
import '../universe/world_builder.dart';
import '../universe/use.dart';
import '../world.dart';
import 'abstract_value_domain.dart';
import 'abstract_value_strategy.dart';

class WrappedAbstractValue implements AbstractValue {
  final AbstractValue _abstractValue;
  const WrappedAbstractValue(this._abstractValue);

  @override
  bool operator ==(var other) {
    if (identical(this, other)) return true;
    if (other is! WrappedAbstractValue) return false;
    return _abstractValue == other._abstractValue;
  }

  @override
  int get hashCode {
    return _abstractValue.hashCode;
  }

  @override
  String toString() => _abstractValue.toString();
}

AbstractValue? unwrapOrNull(WrappedAbstractValue? wrapped) {
  return wrapped?._abstractValue;
}

WrappedAbstractValue? wrapOrNull(AbstractValue? abstractValue) {
  return abstractValue == null ? null : WrappedAbstractValue(abstractValue);
}

class WrappedAbstractValueDomain with AbstractValueDomain {
  final AbstractValueDomain _abstractValueDomain;
  const WrappedAbstractValueDomain(this._abstractValueDomain);

  @override
  AbstractValue get internalTopType =>
      WrappedAbstractValue(_abstractValueDomain.internalTopType);

  @override
  AbstractValue get dynamicType =>
      WrappedAbstractValue(_abstractValueDomain.dynamicType);

  @override
  void writeAbstractValueToDataSink(
    DataSinkWriter sink,
    covariant WrappedAbstractValue value,
  ) {
    _abstractValueDomain.writeAbstractValueToDataSink(
      sink,
      value._abstractValue,
    );
  }

  @override
  AbstractValue readAbstractValueFromDataSource(DataSourceReader source) =>
      WrappedAbstractValue(
        _abstractValueDomain.readAbstractValueFromDataSource(source),
      );

  @override
  String getCompactText(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.getCompactText(value._abstractValue);

  @override
  AbstractBool isFixedLengthJsIndexable(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isFixedLengthJsIndexable(value._abstractValue);

  @override
  AbstractBool isJsIndexableAndIterable(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isJsIndexableAndIterable(value._abstractValue);

  @override
  AbstractBool isJsIndexable(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isJsIndexable(value._abstractValue);

  @override
  MemberEntity? locateSingleMember(
    covariant WrappedAbstractValue receiver,
    Selector selector,
  ) => _abstractValueDomain.locateSingleMember(
    receiver._abstractValue,
    selector,
  );

  @override
  AbstractBool isIn(
    covariant WrappedAbstractValue subset,
    covariant WrappedAbstractValue superset,
  ) =>
      _abstractValueDomain.isIn(subset._abstractValue, superset._abstractValue);

  @override
  AbstractBool needsNoSuchMethodHandling(
    covariant WrappedAbstractValue receiver,
    Selector selector,
  ) => _abstractValueDomain.needsNoSuchMethodHandling(
    receiver._abstractValue,
    selector,
  );

  @override
  AbstractBool isTargetingMember(
    covariant WrappedAbstractValue receiver,
    MemberEntity member,
    Name name,
  ) => _abstractValueDomain.isTargetingMember(
    receiver._abstractValue,
    member,
    name,
  );

  @override
  AbstractValue computeReceiver(Iterable<MemberEntity> members) =>
      WrappedAbstractValue(_abstractValueDomain.computeReceiver(members));

  @override
  PrimitiveConstantValue? getPrimitiveValue(
    covariant WrappedAbstractValue value,
  ) => _abstractValueDomain.getPrimitiveValue(value._abstractValue);

  @override
  AbstractValue createPrimitiveValue(
    covariant WrappedAbstractValue originalValue,
    PrimitiveConstantValue value,
  ) => WrappedAbstractValue(
    _abstractValueDomain.createPrimitiveValue(
      originalValue._abstractValue,
      value,
    ),
  );

  @override
  bool isPrimitiveValue(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPrimitiveValue(value._abstractValue);

  @override
  MemberEntity? getAllocationElement(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.getAllocationElement(value._abstractValue);

  @override
  Object? getAllocationNode(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.getAllocationNode(value._abstractValue);

  @override
  AbstractValue getGeneralization(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.getGeneralization(unwrapOrNull(value))!,
      );

  @override
  bool isSpecializationOf(
    covariant WrappedAbstractValue specialization,
    covariant WrappedAbstractValue generalization,
  ) => _abstractValueDomain.isSpecializationOf(
    specialization._abstractValue,
    generalization._abstractValue,
  );

  @override
  AbstractValue getDictionaryValueForKey(
    covariant WrappedAbstractValue value,
    String key,
  ) => WrappedAbstractValue(
    _abstractValueDomain.getDictionaryValueForKey(value._abstractValue, key),
  );

  @override
  bool containsDictionaryKey(
    covariant WrappedAbstractValue value,
    String key,
  ) => _abstractValueDomain.containsDictionaryKey(value._abstractValue, key);

  @override
  AbstractValue createDictionaryValue(
    covariant WrappedAbstractValue? originalValue,
    Object? allocationNode,
    MemberEntity? allocationElement,
    covariant WrappedAbstractValue key,
    covariant WrappedAbstractValue value,
    covariant Map<String, AbstractValue> mappings,
  ) {
    return WrappedAbstractValue(
      _abstractValueDomain.createDictionaryValue(
        originalValue?._abstractValue,
        allocationNode,
        allocationElement,
        key._abstractValue,
        value._abstractValue,
        {
          for (var entry in mappings.entries)
            entry.key: (entry.value as WrappedAbstractValue)._abstractValue,
        },
      ),
    );
  }

  @override
  bool isDictionary(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isDictionary(value._abstractValue);

  @override
  AbstractValue createRecordValue(
    RecordShape shape,
    List<AbstractValue> types,
  ) {
    AbstractValue abstractValue = _abstractValueDomain.createRecordValue(
      shape,
      types
          .map((e) => (e as WrappedAbstractValue)._abstractValue)
          .toList(growable: false),
    );
    return WrappedAbstractValue(abstractValue);
  }

  @override
  bool isRecord(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isRecord(value._abstractValue);

  @override
  bool recordHasGetter(
    covariant WrappedAbstractValue value,
    String getterName,
  ) => _abstractValueDomain.recordHasGetter(value._abstractValue, getterName);

  @override
  AbstractValue getGetterTypeInRecord(
    covariant WrappedAbstractValue value,
    String getterName,
  ) => WrappedAbstractValue(
    _abstractValueDomain.getGetterTypeInRecord(
      value._abstractValue,
      getterName,
    ),
  );

  @override
  AbstractValue getMapValueType(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.getMapValueType(value._abstractValue),
      );

  @override
  AbstractValue getMapKeyType(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.getMapKeyType(value._abstractValue),
      );

  @override
  AbstractValue createMapValue(
    covariant WrappedAbstractValue? originalValue,
    Object? allocationNode,
    MemberEntity? allocationElement,
    covariant WrappedAbstractValue key,
    covariant WrappedAbstractValue value,
  ) => WrappedAbstractValue(
    _abstractValueDomain.createMapValue(
      originalValue?._abstractValue,
      allocationNode,
      allocationElement,
      key._abstractValue,
      value._abstractValue,
    ),
  );

  @override
  bool isMap(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isMap(value._abstractValue);

  @override
  AbstractValue getSetElementType(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.getSetElementType(value._abstractValue),
      );

  @override
  AbstractValue createSetValue(
    covariant WrappedAbstractValue? originalValue,
    Object? allocationNode,
    MemberEntity? allocationElement,
    covariant WrappedAbstractValue elementType,
  ) => WrappedAbstractValue(
    _abstractValueDomain.createSetValue(
      originalValue?._abstractValue,
      allocationNode,
      allocationElement,
      elementType._abstractValue,
    ),
  );

  @override
  bool isSet(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isSet(value._abstractValue);

  @override
  int? getContainerLength(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.getContainerLength(value._abstractValue);

  @override
  AbstractValue getContainerElementType(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.getContainerElementType(value._abstractValue),
      );

  @override
  AbstractValue createContainerValue(
    covariant WrappedAbstractValue? originalValue,
    Object? allocationNode,
    MemberEntity? allocationElement,
    covariant WrappedAbstractValue elementType,
    int? length,
  ) => WrappedAbstractValue(
    _abstractValueDomain.createContainerValue(
      originalValue?._abstractValue,
      allocationNode,
      allocationElement,
      elementType._abstractValue,
      length,
    ),
  );

  @override
  bool isContainer(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isContainer(value._abstractValue);

  @override
  AbstractValue computeAbstractValueForConstant(
    covariant ConstantValue value,
  ) => WrappedAbstractValue(
    _abstractValueDomain.computeAbstractValueForConstant(value),
  );

  @override
  AbstractValue? getAbstractValueForNativeMethodParameterType(DartType type) {
    return wrapOrNull(
      _abstractValueDomain.getAbstractValueForNativeMethodParameterType(type),
    );
  }

  @override
  AbstractBool containsAll(covariant WrappedAbstractValue a) =>
      _abstractValueDomain.containsAll(a._abstractValue);

  @override
  AbstractBool areDisjoint(
    covariant WrappedAbstractValue a,
    covariant WrappedAbstractValue b,
  ) => _abstractValueDomain.areDisjoint(a._abstractValue, b._abstractValue);

  @override
  AbstractValue intersection(
    covariant WrappedAbstractValue a,
    covariant WrappedAbstractValue b,
  ) => WrappedAbstractValue(
    _abstractValueDomain.intersection(a._abstractValue, b._abstractValue),
  );

  @override
  AbstractValue unionOfMany(covariant Iterable<AbstractValue> values) {
    List<AbstractValue> unwrappedValues =
        values
            .map((element) => (element as WrappedAbstractValue)._abstractValue)
            .toList();
    return WrappedAbstractValue(
      _abstractValueDomain.unionOfMany(unwrappedValues),
    );
  }

  @override
  AbstractValue union(
    covariant WrappedAbstractValue a,
    covariant WrappedAbstractValue b,
  ) => WrappedAbstractValue(
    _abstractValueDomain.union(a._abstractValue, b._abstractValue),
  );

  @override
  AbstractBool isPrimitiveOrNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPrimitiveOrNull(value._abstractValue);

  @override
  AbstractBool isStringOrNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isStringOrNull(value._abstractValue);

  @override
  AbstractBool isString(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isString(value._abstractValue);

  @override
  AbstractBool isBooleanOrNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isBooleanOrNull(value._abstractValue);

  @override
  AbstractBool isBoolean(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isBoolean(value._abstractValue);

  @override
  AbstractBool isTruthy(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isTruthy(value._abstractValue);

  @override
  AbstractBool isNumberOrNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isNumberOrNull(value._abstractValue);

  @override
  AbstractBool isNumber(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isNumber(value._abstractValue);

  @override
  AbstractBool isIntegerOrNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isIntegerOrNull(value._abstractValue);

  @override
  AbstractBool isPositiveIntegerOrNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPositiveIntegerOrNull(value._abstractValue);

  @override
  AbstractBool isPositiveInteger(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPositiveInteger(value._abstractValue);

  @override
  AbstractBool isUInt31(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isUInt31(value._abstractValue);

  @override
  AbstractBool isUInt32(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isUInt32(value._abstractValue);

  @override
  AbstractBool isInteger(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isInteger(value._abstractValue);

  @override
  AbstractBool isInterceptor(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isInterceptor(value._abstractValue);

  @override
  AbstractBool isPrimitiveString(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPrimitiveString(value._abstractValue);

  @override
  AbstractBool isArray(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isArray(value._abstractValue);

  @override
  AbstractBool isMutableIndexable(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isMutableIndexable(value._abstractValue);

  @override
  AbstractBool isMutableArray(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isMutableArray(value._abstractValue);

  @override
  AbstractBool isExtendableArray(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isExtendableArray(value._abstractValue);

  @override
  AbstractBool isFixedArray(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isFixedArray(value._abstractValue);

  @override
  AbstractBool isIndexablePrimitive(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isIndexablePrimitive(value._abstractValue);

  @override
  AbstractBool isPrimitiveBoolean(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPrimitiveBoolean(value._abstractValue);

  @override
  AbstractBool isPrimitiveNumber(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPrimitiveNumber(value._abstractValue);

  @override
  AbstractBool isPrimitive(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isPrimitive(value._abstractValue);

  @override
  AbstractBool isNull(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isNull(value._abstractValue);

  @override
  AbstractBool isLateSentinel(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isLateSentinel(value._abstractValue);

  @override
  ClassEntity? getExactClass(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.getExactClass(value._abstractValue);

  @override
  AbstractBool isExact(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isExact(value._abstractValue);

  @override
  AbstractBool isEmpty(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isEmpty(value._abstractValue);

  @override
  AbstractBool isInstanceOf(
    covariant WrappedAbstractValue value,
    ClassEntity cls,
  ) => _abstractValueDomain.isInstanceOf(value._abstractValue, cls);

  @override
  AbstractBool containsOnlyType(
    covariant WrappedAbstractValue value,
    ClassEntity cls,
  ) => _abstractValueDomain.containsOnlyType(value._abstractValue, cls);

  @override
  AbstractBool containsType(
    covariant WrappedAbstractValue value,
    ClassEntity cls,
  ) => _abstractValueDomain.containsType(value._abstractValue, cls);

  @override
  AbstractValue includeNull(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.includeNull(value._abstractValue),
      );

  @override
  AbstractValue excludeNull(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.excludeNull(value._abstractValue),
      );

  @override
  AbstractValue includeLateSentinel(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.includeLateSentinel(value._abstractValue),
      );

  @override
  AbstractValue excludeLateSentinel(covariant WrappedAbstractValue value) =>
      WrappedAbstractValue(
        _abstractValueDomain.excludeLateSentinel(value._abstractValue),
      );

  @override
  AbstractBool couldBeTypedArray(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.couldBeTypedArray(value._abstractValue);

  @override
  AbstractBool isTypedArray(covariant WrappedAbstractValue value) =>
      _abstractValueDomain.isTypedArray(value._abstractValue);

  @override
  AbstractValue createNullableSubtype(ClassEntity cls) =>
      WrappedAbstractValue(_abstractValueDomain.createNullableSubtype(cls));

  @override
  AbstractValue createNonNullSubtype(ClassEntity cls) =>
      WrappedAbstractValue(_abstractValueDomain.createNonNullSubtype(cls));

  @override
  AbstractValue createNonNullSubclass(ClassEntity cls) =>
      WrappedAbstractValue(_abstractValueDomain.createNonNullSubclass(cls));

  @override
  AbstractValue createNullableExact(ClassEntity cls) =>
      WrappedAbstractValue(_abstractValueDomain.createNullableExact(cls));

  @override
  AbstractValue createNonNullExact(ClassEntity cls) =>
      WrappedAbstractValue(_abstractValueDomain.createNonNullExact(cls));

  @override
  AbstractValueWithPrecision createFromStaticType(DartType type) {
    var unwrapped = _abstractValueDomain.createFromStaticType(type);
    return AbstractValueWithPrecision(
      WrappedAbstractValue(unwrapped.abstractValue),
      unwrapped.isPrecise,
    );
  }

  @override
  AbstractValue get asyncStarStreamType =>
      WrappedAbstractValue(_abstractValueDomain.asyncStarStreamType);

  @override
  AbstractValue get asyncFutureType =>
      WrappedAbstractValue(_abstractValueDomain.asyncFutureType);

  @override
  AbstractValue get syncStarIterableType =>
      WrappedAbstractValue(_abstractValueDomain.syncStarIterableType);

  @override
  AbstractValue get emptyType =>
      WrappedAbstractValue(_abstractValueDomain.emptyType);

  @override
  AbstractValue get constMapType =>
      WrappedAbstractValue(_abstractValueDomain.constMapType);

  @override
  AbstractValue get constSetType =>
      WrappedAbstractValue(_abstractValueDomain.constSetType);

  @override
  AbstractValue get constListType =>
      WrappedAbstractValue(_abstractValueDomain.constListType);

  @override
  AbstractValue get positiveIntType =>
      WrappedAbstractValue(_abstractValueDomain.positiveIntType);

  @override
  AbstractValue get uint32Type =>
      WrappedAbstractValue(_abstractValueDomain.uint32Type);

  @override
  AbstractValue get uint31Type =>
      WrappedAbstractValue(_abstractValueDomain.uint31Type);

  @override
  AbstractValue get fixedListType =>
      WrappedAbstractValue(_abstractValueDomain.fixedListType);

  @override
  AbstractValue get growableListType =>
      WrappedAbstractValue(_abstractValueDomain.growableListType);

  @override
  AbstractValue get mutableArrayType =>
      WrappedAbstractValue(_abstractValueDomain.mutableArrayType);

  @override
  AbstractValue get nullType =>
      WrappedAbstractValue(_abstractValueDomain.nullType);

  @override
  AbstractValue get nonNullType =>
      WrappedAbstractValue(_abstractValueDomain.nonNullType);

  @override
  AbstractValue get lateSentinelType =>
      WrappedAbstractValue(_abstractValueDomain.lateSentinelType);

  @override
  AbstractValue get mapType =>
      WrappedAbstractValue(_abstractValueDomain.mapType);

  @override
  AbstractValue get setType =>
      WrappedAbstractValue(_abstractValueDomain.setType);

  @override
  AbstractValue get listType =>
      WrappedAbstractValue(_abstractValueDomain.listType);

  @override
  AbstractValue get stringType =>
      WrappedAbstractValue(_abstractValueDomain.stringType);

  @override
  AbstractValue get numType =>
      WrappedAbstractValue(_abstractValueDomain.numType);

  @override
  AbstractValue get numNotIntType =>
      WrappedAbstractValue(_abstractValueDomain.numNotIntType);

  @override
  AbstractValue get intType =>
      WrappedAbstractValue(_abstractValueDomain.intType);

  @override
  AbstractValue get boolType =>
      WrappedAbstractValue(_abstractValueDomain.boolType);

  @override
  AbstractValue get functionType =>
      WrappedAbstractValue(_abstractValueDomain.functionType);

  @override
  AbstractValue get recordType =>
      WrappedAbstractValue(_abstractValueDomain.recordType);

  @override
  AbstractValue get typeType =>
      WrappedAbstractValue(_abstractValueDomain.typeType);

  @override
  Iterable<DynamicCallTarget> findRootsOfTargets(
    covariant WrappedAbstractValue receiver,
    Selector selector,
    MemberHierarchyBuilder memberHierarchyBuilder,
  ) => _abstractValueDomain.findRootsOfTargets(
    receiver._abstractValue,
    selector,
    memberHierarchyBuilder,
  );

  @override
  bool isInvalidRefinement(
    covariant WrappedAbstractValue before,
    covariant WrappedAbstractValue after,
  ) {
    return _abstractValueDomain.isInvalidRefinement(
      before._abstractValue,
      after._abstractValue,
    );
  }
}

class WrappedAbstractValueStrategy
    implements AbstractValueStrategy<WrappedAbstractValueDomain> {
  final AbstractValueStrategy _abstractValueStrategy;
  const WrappedAbstractValueStrategy(this._abstractValueStrategy);

  @override
  WrappedAbstractValueDomain createDomain(JClosedWorld closedWorld) {
    return WrappedAbstractValueDomain(
      _abstractValueStrategy.createDomain(closedWorld),
    );
  }

  @override
  SelectorConstraintsStrategy createSelectorStrategy(
    WrappedAbstractValueDomain domain,
  ) {
    return WrappedSelectorStrategy(
      _abstractValueStrategy.createSelectorStrategy(
        domain._abstractValueDomain,
      ),
    );
  }
}

class WrappedSelectorStrategy implements SelectorConstraintsStrategy {
  final SelectorConstraintsStrategy _selectorConstraintsStrategy;
  const WrappedSelectorStrategy(this._selectorConstraintsStrategy);

  @override
  UniverseSelectorConstraints createSelectorConstraints(
    Selector selector,
    Object? initialConstraint,
  ) {
    return WrappedUniverseSelectorConstraints(
      _selectorConstraintsStrategy.createSelectorConstraints(
        selector,
        initialConstraint == null
            ? null
            : (initialConstraint as WrappedAbstractValue)._abstractValue,
      ),
    );
  }

  @override
  bool appliedUnnamed(
    DynamicUse dynamicUse,
    MemberEntity member,
    covariant JClosedWorld world,
  ) {
    return _selectorConstraintsStrategy.appliedUnnamed(
      dynamicUse.withReceiverConstraint(
        unwrapOrNull(dynamicUse.receiverConstraint as WrappedAbstractValue?),
      ),
      member,
      world,
    );
  }
}

class WrappedUniverseSelectorConstraints
    implements UniverseSelectorConstraints {
  final UniverseSelectorConstraints _universeSelectorConstraints;
  const WrappedUniverseSelectorConstraints(this._universeSelectorConstraints);

  @override
  bool addReceiverConstraint(Object? constraint) =>
      _universeSelectorConstraints.addReceiverConstraint(
        constraint == null
            ? null
            : (constraint as WrappedAbstractValue)._abstractValue,
      );

  @override
  bool needsNoSuchMethodHandling(Selector selector, World world) =>
      _universeSelectorConstraints.needsNoSuchMethodHandling(selector, world);

  @override
  bool canHit(MemberEntity element, Name name, World world) =>
      _universeSelectorConstraints.canHit(element, name, world);

  @override
  String toString() => 'WrappedUniverseSelectorConstraints:$hashCode';
}
